﻿using Niknak.Services.ServiceCore;
using Niknak.Services.ServiceCore.Wcf;
using Niknak.Services.TaskScheduler;
using Niknak.Services.TaskScheduler.Interfaces.DataModel;
using Niknak.Services.TaskScheduler.UI.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;

namespace Niknak.Services.TaskScheduler.UI.WebControls
{
    public class AuditLog<ExceptionHandlerType, WcfConfigurationSettings, ScheduledTaskType, AuditLogType, AuditLogEntryType> : EmbeddedUserControl
        where ExceptionHandlerType : IExceptionHandler, new()
        where WcfConfigurationSettings : IWcfConfig, new()
        where ScheduledTaskType : IScheduledTask, new()
        where AuditLogType : IAuditLog<AuditLogEntryType>, new()
        where AuditLogEntryType : IAuditLogEntry
    {
        #region Controls
        protected global::System.Web.UI.WebControls.MultiView uiMlvLogs;
        protected global::System.Web.UI.WebControls.View uiViwLogsList;
        protected global::System.Web.UI.WebControls.DropDownList uiDdlTask;
        protected global::System.Web.UI.WebControls.Button uiBtnFilter;
        protected global::System.Web.UI.WebControls.Button uiBtnRemove;
        protected global::System.Web.UI.WebControls.Repeater uiRptAllLogs;
        protected global::System.Web.UI.HtmlControls.HtmlGenericControl uiDivPaging;
        protected global::System.Web.UI.WebControls.Repeater uiRptPageNumbers;
        protected global::System.Web.UI.WebControls.View uiViwViewLog;
        protected global::System.Web.UI.WebControls.Literal uiLitOutcome;
        protected global::System.Web.UI.WebControls.Literal uiLitCompletedEventStatus;
        protected global::System.Web.UI.WebControls.Button uiBtnRaiseCompletedEvent;
        protected global::System.Web.UI.WebControls.Literal uiLitRaiseCompletedEventOutcome;
        protected global::System.Web.UI.WebControls.Literal uiLitTaskName;
        protected global::System.Web.UI.WebControls.Literal uiLitIterationDate;
        protected global::System.Web.UI.WebControls.Literal uiLitStartDate;
        protected global::System.Web.UI.WebControls.Literal uiLitFinishDate;
        protected global::System.Web.UI.WebControls.Repeater uiRptEntries;
        #endregion

        private ScheduledTaskType ScheduledTask = new ScheduledTaskType();
        private AuditLogType AuditLogInstance = new AuditLogType();

        private Guid? QsAuditLogId
        {
            get
            {
                string rawGuid = Request.QueryString["logId"];

                if (!string.IsNullOrEmpty(rawGuid))
                {
                    Guid outGuid;
                    if (Guid.TryParse(rawGuid, out outGuid))
                        return outGuid;
                }

                return null;
            }
        }

        private Guid? QsDeleteLogId
        {
            get
            {
                string rawGuid = Request.QueryString["deleteLogId"];

                if (!string.IsNullOrEmpty(rawGuid))
                {
                    Guid outGuid;
                    if (Guid.TryParse(rawGuid, out outGuid))
                        return outGuid;
                }

                return null;
            }
        }

        private Guid? QsScheduledTaskId
        {
            get
            {
                string rawGuid = Request.QueryString["taskId"];

                if (!string.IsNullOrEmpty(rawGuid))
                {
                    Guid outGuid;
                    if (Guid.TryParse(rawGuid, out outGuid))
                        return outGuid;
                }

                return null;
            }
        }

        private int QsPageIndex
        {
            get
            {
                string rawIndex = Request.QueryString["pageIndex"];
                int outIndex;
                if (!string.IsNullOrEmpty(rawIndex) && int.TryParse(rawIndex, out outIndex))
                    return outIndex;
                return 0;
            }
        }

        public AuditLog()
            : base("AuditLog.ascx")
        {
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            uiBtnFilter.Click += (s, a) => Response.Redirect(Request.Url.AbsolutePath + "?taskId=" + uiDdlTask.SelectedItem.Value);
            uiBtnRemove.Click += (s, a) =>
            {
                //remove log items for this task id (or all if none selected)
                if (uiDdlTask.SelectedIndex == 0)
                    AuditLogInstance.RemoveAll();
                else
                    AuditLogInstance.RemoveByTaskId(Guid.Parse(uiDdlTask.SelectedItem.Value));

                Response.Redirect(Request.Url.AbsolutePath + "?taskId=" + uiDdlTask.SelectedItem.Value);
            };
            uiBtnRaiseCompletedEvent.Click += (s, a) =>
            {
                AuditLogType log = (AuditLogType)AuditLogInstance.GetAuditLogById(QsAuditLogId.Value);
                bool result = WcfEndpointHelper<WcfConfigurationSettings, ExceptionHandlerType>.RaiseIterationCompletedEvent(log.ScheduledTaskId, log.IterationDate);
                uiLitRaiseCompletedEventOutcome.Text = result ? "Command accepted, see Event Log for details" : "Command failed";
            };

            if (!IsPostBack && QsAuditLogId.HasValue)
                PopulateLog(QsAuditLogId.Value);
            else if (!IsPostBack && QsDeleteLogId.HasValue)
                DeleteLog(QsDeleteLogId.Value);
            else if (!IsPostBack)
                PopulateLogs();
        }

        private void PopulateLogs()
        {
            List<AuditLogType> logs;
            int returnedLogsCount = 0;

            if (QsScheduledTaskId.HasValue && QsScheduledTaskId.Value != Guid.Empty)
            {
                returnedLogsCount = (int)AuditLogInstance.GetAuditLogsByScheduledTaskId(QsScheduledTaskId.Value).Count();
                logs = AuditLogInstance.GetAuditLogsByScheduledTaskId(QsScheduledTaskId.Value)
                    .Cast<AuditLogType>()
                    .OrderBy(a => a.TaskOutcome == Niknak.Services.TaskScheduler.Enums.TaskOutcome.InProgress ? 0 : 1)
                    .ThenByDescending(a => a.FinishDate)
                    .Skip(Constants.PAGESIZE * QsPageIndex)
                    .Take(Constants.PAGESIZE)
                    .ToList();
            }
            else
            {
                returnedLogsCount = (int)AuditLogInstance.GetAllAuditLogs().Count();
                logs = AuditLogInstance.GetAllAuditLogs()
                    .Cast<AuditLogType>()
                    .OrderBy(a => a.TaskOutcome == Niknak.Services.TaskScheduler.Enums.TaskOutcome.InProgress ? 0 : 1)
                    .ThenByDescending(a => a.FinishDate)
                    .Skip(Constants.PAGESIZE * QsPageIndex)
                    .Take(Constants.PAGESIZE)
                    .ToList();

            }

            uiRptAllLogs.DataSource = logs;
            uiRptAllLogs.DataBind();

            Literal uiLitTaskName, uiLitIterationDate, uiLitStartDate, uiLitFinishDate, uiLitOutcome, uiLitDeleteLink, uiLitDetailsLink;
            AuditLogType log;

            foreach (RepeaterItem item in uiRptAllLogs.Items)
            {
                uiLitTaskName = item.FindControl("uiLitTaskName") as Literal;
                uiLitIterationDate = item.FindControl("uiLitIterationDate") as Literal;
                uiLitStartDate = item.FindControl("uiLitStartDate") as Literal;
                uiLitFinishDate = item.FindControl("uiLitFinishDate") as Literal;
                uiLitOutcome = item.FindControl("uiLitOutcome") as Literal;
                uiLitDeleteLink = item.FindControl("uiLitDeleteLink") as Literal;
                uiLitDetailsLink = item.FindControl("uiLitDetailsLink") as Literal;
                log = logs[item.ItemIndex];

                uiLitTaskName.Text = ScheduledTask.GetByTaskId(log.ScheduledTaskId).Name;
                uiLitIterationDate.Text = log.IterationDate > DateTime.MinValue ? log.IterationDate.ToString("yyyy-MM-dd HH:mm:ss") : "TBD";
                uiLitStartDate.Text = log.StartDate.ToString("yyyy-MM-dd HH:mm:ss");
                uiLitFinishDate.Text = log.FinishDate.ToString("yyyy-MM-dd HH:mm:ss");
                uiLitOutcome.Text = string.Format(uiLitOutcome.Text, Page.ClientScript.GetWebResourceUrl(this.GetType(), "Niknak.Services.TaskScheduler.UI.WebControls.Assets.icon_" + log.TaskOutcome.ToString() + ".png"));
                uiLitDeleteLink.Text = string.Format(uiLitDeleteLink.Text, log.AuditLogId, Page.ClientScript.GetWebResourceUrl(this.GetType(), "Niknak.Services.TaskScheduler.UI.WebControls.Assets.icon_Delete.png"));
                uiLitDetailsLink.Text = string.Format(uiLitDetailsLink.Text, log.AuditLogId);
            }

            uiDdlTask.Items.Clear();
            uiDdlTask.Items.Add(new ListItem());
            ScheduledTask.GetAllScheduledTasks().OrderBy(st => st.Name).ToList().ForEach(s => uiDdlTask.Items.Add(new ListItem(s.Name, s.ScheduledTaskId.ToString())));

            if (QsScheduledTaskId.HasValue && QsScheduledTaskId.Value != Guid.Empty)
                uiDdlTask.Items.FindByValue(QsScheduledTaskId.Value.ToString()).Selected = true;

            //paging
            List<int> pageIndexes = new List<int>();
            for (int i = 0; i < Utils.CalculateNumberOfPages(returnedLogsCount, Constants.PAGESIZE); i++)
                pageIndexes.Add(i);

            uiRptPageNumbers.DataSource = pageIndexes;
            uiRptPageNumbers.DataBind();

            Literal uiLitPageNumber;

            foreach (RepeaterItem item in uiRptPageNumbers.Items)
            {
                uiLitPageNumber = item.FindControl("uiLitPageNumber") as Literal;
                uiLitPageNumber.Text = string.Format(
                    uiLitPageNumber.Text,
                    pageIndexes[item.ItemIndex],
                    QsScheduledTaskId.HasValue ? QsScheduledTaskId.Value.ToString() : string.Empty,
                    pageIndexes[item.ItemIndex] == QsPageIndex ? string.Format("<strong>{0}</strong>", pageIndexes[item.ItemIndex] + 1) : (pageIndexes[item.ItemIndex] + 1).ToString(),
                    pageIndexes[item.ItemIndex] != pageIndexes[pageIndexes.Count - 1] ? ", " : string.Empty
                );
            }

            uiMlvLogs.SetActiveView(uiViwLogsList);
        }

        private void PopulateLog(Guid logId)
        {
            AuditLogType log = (AuditLogType)AuditLogInstance.GetAuditLogById(logId);

            if (log == null)
                PopulateLogs();

            ScheduledTaskType task = (ScheduledTaskType)ScheduledTask.GetByTaskId(log.ScheduledTaskId);

            uiLitOutcome.Text = uiLitOutcome.Text = string.Format(uiLitOutcome.Text, Page.ClientScript.GetWebResourceUrl(this.GetType(), "Niknak.Services.TaskScheduler.UI.WebControls.Assets.icon_" + log.TaskOutcome.ToString() + ".png"), Utils.GetEnumDescription(log.TaskOutcome));
            uiLitCompletedEventStatus.Text = string.Format(uiLitCompletedEventStatus.Text, Page.ClientScript.GetWebResourceUrl(this.GetType(), "Niknak.Services.TaskScheduler.UI.WebControls.Assets.icon_" + log.CompletedEventStatus.ToString() + ".png"), Utils.GetEnumDescription(log.CompletedEventStatus));
            uiBtnRaiseCompletedEvent.Enabled = log.CompletedEventStatus != Niknak.Services.TaskScheduler.Enums.CompletedEventStatus.InProgress && WcfEndpointHelper<WcfConfigurationSettings, ExceptionHandlerType>.IsEndpointOnline();
            uiLitTaskName.Text = string.Format(uiLitTaskName.Text, log.ScheduledTaskId, task.Name, ScheduledTask.EditPageUrl);
            uiLitIterationDate.Text = log.IterationDate > DateTime.MinValue ? log.IterationDate.ToString("yyyy-MM-dd HH:mm:ss") : "TBD";
            uiLitStartDate.Text = log.StartDate.ToString("yyyy-MM-dd HH:mm:ss");
            uiLitFinishDate.Text = log.FinishDate.ToString("yyyy-MM-dd HH:mm:ss");

            List<AuditLogEntryType> entries = log.AuditLogEntries.OrderBy(e => e.EntryDate != null ? e.EntryDate : DateTime.MinValue).ToList();

            uiRptEntries.DataSource = entries;
            uiRptEntries.DataBind();

            Literal uiLitEntryType, uiLitEntryDate, uiLitMessage;
            AuditLogEntryType entry;

            foreach (RepeaterItem item in uiRptEntries.Items)
            {
                uiLitEntryType = item.FindControl("uiLitEntryType") as Literal;
                uiLitEntryDate = item.FindControl("uiLitEntryDate") as Literal;
                uiLitMessage = item.FindControl("uiLitMessage") as Literal;
                entry = entries[item.ItemIndex];

                uiLitEntryType.Text = string.Format(uiLitEntryType.Text, Page.ClientScript.GetWebResourceUrl(this.GetType(), "Niknak.Services.TaskScheduler.UI.WebControls.Assets.icon_" + (entry.AuditLogEntryType).ToString() + ".png"));
                uiLitEntryDate.Text = entry.EntryDate.ToString("yyyy-MM-dd HH:mm:ss");
                uiLitMessage.Text = entry.Message.Replace("\n", "<br/>");
            }

            uiMlvLogs.SetActiveView(uiViwViewLog);
        }

        private void DeleteLog(Guid logId)
        {
            if (logId == Guid.Empty)
            {
                Response.Redirect(Request.Url.AbsolutePath, false);
                return;
            }

            AuditLogType log = (AuditLogType)AuditLogInstance.GetAuditLogById(logId);

            if (log == null)
            {
                Response.Redirect(Request.Url.AbsolutePath, false);
                return;
            }

            ((AuditLogType)AuditLogInstance).Remove(logId);
            Response.Redirect(Request.Url.AbsolutePath, false);
        }
    }
}
